﻿using System;
using System.Collections.Generic;
using System.DirectoryServices.ActiveDirectory;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Shapes;
using Ab3d;
using Ab3d.Utilities;
using Ab3d.Visuals;
using Newtonsoft.Json;
using Scad4.Models;
using Scad4.Resources;
using Scad4.Services;
using Scad4.Toolkits;
using Scad4.ViewModels;
using Scad4.Visuals;
using WpfApp3d.ViewModels;

namespace WpfApp3d
{
   
    /// <summary>
    /// Test.xaml 的交互逻辑
    /// </summary>
    public partial class Test : System.Windows.Window
    {
        public static Point3D GetCenter(IList<Point3D>? points)
        {
            if (points == null || points.Count == 0) return new Point3D(0, 0, 0);
            var x = 0.0;
            var y = 0.0;
            var z = 0.0;
            foreach (var point in points)
            {
                x += point.X;
                y += point.Y;
                z += point.Z;
            }
            var scale = 1.0 / points.Count;
            return new Point3D(x * scale, y * scale, z * scale);
        }

        public Test()
        {
            this.DataContext = new TestViewModel();
            InitializeComponent();
            this.Loaded += Test_Loaded;
            MainCameraCircles.UseZUpAxis();
           
        }

        const double height = 30.2;

        private void Test_Loaded(object sender, RoutedEventArgs e)
        {
            var path = @"D:\Desktop\2.json";//@"D:\Desktop\案例1.json";

            var val = File.ReadAllText(path);

            var baseData = JsonConvert.DeserializeObject<ScadData>(val);
            var data = JsonTool.DeserializeFromFile<Scad4.Models.ScadData>(path);
            var project = new ScadProject(path, data);
            //y=z z=-y;
            //var xAverage = baseData.IdentifyAreas.Sum(s => s.X/100) / 2;
            //var yAverage = baseData.IdentifyAreas.Sum(s => s.Y/100) / 2;
            var pontis = baseData.IdentifyAreas.Select(s => { return new Point3D(s.X/100, s.Z/100, -s.Y/100); }).ToList();
            var cameraPosition= GetCenter(pontis);

            this.Camera1.RotationCenterPosition = new Point3D(cameraPosition.X+5, cameraPosition.Y+5, cameraPosition.Z+5);//cameraPosition;
            this.Camera1.TargetPosition = new Point3D(cameraPosition.X,cameraPosition.Y,cameraPosition.Z);
            this.Camera1.Distance = 400;
            //this.Camera1.Offset = new Vector3D(-2, -2, -2);
            baseData.Construction.Walls.ForEach(f => {

               
                var tp = f.Edges.Select(s => { return new Point(s.X/100, s.Y/100); }).ToList();
                var tp1 = f.Edges.Select(s => { return new Point3D(s.X/100, s.Y/100,(s.Z+50)/100); }).ToList();
                var tp2 = f.Edges.Select(s => { return new Point3D(s.X / 100, s.Y / 100, (s.Z / 100)+ height); }).ToList();

                if (f.InLines != null&&f.InLines.Any())
                {
                    Create3D(tp, tp1, f.InLines[0].Select(x => { return new Point(x.X/100, x.Y/100); }).ToList(),true);//底面
                    Create3D(tp, tp2, f.InLines[0].Select(x => { return new Point(x.X/100, x.Y/100); }).ToList(),true);//顶面
                }
                else
                {
                    Create3D(tp, tp1, null);//底面
                    Create3D(tp, tp2, null);//顶面
                }
             


                //侧面
                CreateVerticalFlats(new MeshGeometry3D(), tp);

                //地板面

                var floor = baseData.Construction.groundFloor.SpaceHeights;
                foreach (var item in floor)
                {
                    foreach (var zone in item.zoneHeights)
                    {
                        var zonePoints = zone.pts.Select(x => new Point(x.X/100, x.Y/100)).ToList();
                        Create3D(zonePoints, zone.pts.Select(x => new Point3D(x.X / 100, x.Y / 100, (x.Z / 100))).ToList(),null,brush:Brushes.LightSalmon);
                    }
                }



            });

            //groundfloor
            var temp = baseData.Construction.groundFloor.Range.pts;
            var fpoints= baseData.Construction.groundFloor.Range.pts.Select(x => new Point(x.X/100, x.Y/100)).ToList();
            Create3D(fpoints, temp.Select(x=>new Point3D(x.X/100,x.Y/100,(x.Z/100)-5)).ToList(), null);

            CreateVerticalFlats(new MeshGeometry3D(), fpoints, upperHeight: 0,lowerHeight:-5);



            //门窗

            var winDatas = baseData.Construction.BaseWindow;

            // winDatas = new List<BaseWindow>() { winDatas.First() };
            int i = 1;
            foreach (var item in winDatas)
            {
                var inPoints = item.InPoints.Select(x=>new Point(x.X*0.01,x.Y*0.01)).ToList();
                var outPoints = item.OutPoints.Select(x => new Point(x.X*0.01, x.Y*0.01)).ToList();
                var winPoints= item.WinPoints.Select(x => new Point(x.X * 0.01, x.Y * 0.01)).ToList();

                //计算窗户下墙面
                var wallHeight = (height - (item.WinHeight * 0.01))*0.5;

                //Create3D(disPoints, Points, null);

                //var disPoints= SD4_WindowTool.GetWallEdges(inPoints, outPoints);
                //var Points = SD4_MeshTool.Point2DTo3D(disPoints, 0);
                StandardTransform3D standard = new StandardTransform3D();
                standard.TranslateX = item.InsertionPoint.X * 0.01;
                standard.TranslateY = item.InsertionPoint.Y * 0.01;
                standard.TranslateZ = item.InsertionPoint.Z * 0.01;

                //standard.RotateZ = 90;
              
                //Create3D(inPoints, Point2DTo3D(inPoints,wallHeight), null,standardTransform:standard);
              
               // CreateVerticalFlats(new MeshGeometry3D(), inPoints, upperHeight: wallHeight,standardTransform: standard);
                //CreateVerticalFlats(new MeshGeometry3D(), outPoints, upperHeight: wallHeight, standardTransform: standard);
                inPoints.AddRange(outPoints);
               // Create3D(inPoints, Point2DTo3D(inPoints, wallHeight), null, standardTransform: standard);
                CreateVerticalFlats(new MeshGeometry3D(), inPoints, upperHeight: wallHeight,standardTransform:standard);
                Create3D(inPoints, Point2DTo3D(inPoints, wallHeight), null, standardTransform: standard, brush: Brushes.Black);
                //门窗上墙
                CreateVerticalFlats(new MeshGeometry3D(), inPoints,lowerHeight:27, upperHeight: height, standardTransform: standard);
                Create3D(inPoints, Point2DTo3D(inPoints, 27), null, standardTransform: standard, brush: Brushes.Black);



                //窗户导入
                var point1 = winPoints[i - 1];
                var point2 = winPoints[i];
                var arrow = point2 - point1;
                var winWidth = arrow.Length;

                var name = SD4_WindowTool.GetResourceName(new ScadUnit(0.01), winWidth, item.WinHeight*Unit, item.SellHeight*Unit, out var frameWidth);
                var modelGroup = SD4_MeshTool.InitModel(String.Format(ModelPath, name));

                var bound = modelGroup.Bounds;

                int frameCount = 1;
                var frameStep = arrow;
                if (winWidth > frameWidth)
                {
                    frameCount = (int)Math.Ceiling(winWidth / frameWidth);
                    frameStep /= frameCount;
                    winWidth /= frameCount;
                }

                var scaleX = winWidth / bound.SizeX;
                var scaleY = item.WinHeight * Unit / bound.SizeY;

                for (int j = 0; j < frameCount; j++)
                {

                    var transform = Matrix3D.Identity;
                    //设置尺寸
                    transform.Scale(new Vector3D(scaleX, scaleY, 1));
                    //设置Z轴向上
                    transform.Rotate(new Quaternion(new Vector3D(1, 0, 0), 90));
                    //设置反向
                    if (item.Reverse)
                    {
                        transform.RotateAt(
                            new Quaternion(new Vector3D(0, 0, 1), 180),
                            new Point3D(bound.SizeX * scaleX * 0.5f, 0, 0));
                    }
                    //设置旋转角度
                    //transform.Rotate(new Quaternion(new Vector3D(0, 0, arrow.Y < 0 ? -1 : 1), winAngle));
                    transform.Rotate(new Quaternion(new Vector3D(0, 0, 1), item.Rotation));

                    transform.Translate(new Vector3D(
                        point1.X + frameStep.X * j,
                        point1.Y + frameStep.Y * j,
                        item.SellHeight*0.01));

                    //modelGroup.Transform = new MatrixTransform3D(transform);

                    //    StandardTransform3D standard = new StandardTransform3D();
                    //standard.TranslateX = item.InsertionPoint.X * 0.01;
                    //standard.TranslateY = item.InsertionPoint.Y * 0.01;
                    //standard.TranslateZ = item.InsertionPoint.Z * 0.01;

                    //var tem2p=  transform* standard.Transform.Value;
                    Matrix3D m3 = Matrix3D.Multiply(transform, standard.Transform.Value);

                    this.MainViewRoot.Children.Add(new ModelVisual3D() {  Content= modelGroup,Transform=new MatrixTransform3D(m3) });
                }



                #region 门创建和导入


                //初始化数据
                var filePath = @"";
            
                if (project.Data.Construction.Doors == null) return;
                var modelDoor = this.MainViewRoot.Children;
                //foreach (var door in project.Data.Construction.Doors)
                //{
                //    var vm = new ScadDoorViewModel(door, new ResourceModelService(new LoggerService()));
                //    var visual = new VisualDoor(project, vm);
                //    modelDoor.Add(visual);
                //    ////生成门顶墙
                //    //modelDoor.Add(new VisualDoorWallUpper(visual));
                //    ////生成门顶板
                //    //modelDoor.Add(new VisualDoorFloorUpper(visual));
                //    ////生成门底板
                //    //modelDoor.Add(new VisualDoorFloorLower(visual));
                //}

                //判断门数量
                //计算门页数量
                var tool = new SD4_DoorTool(new ScadUnit(0.01));
                foreach (var door in project.Data.Construction.Doors)
                {
                    var LeafNumber = door.Leaf.Num;
                    if (LeafNumber <= 0)
                    {
                        LeafNumber = tool.CalLeafNumber(door.Type, door.Jambs.Type, door.Width, door.Jambs.Thickness);
                    }

                    StandardTransform3D standard1 = new StandardTransform3D();
                    standard1.TranslateX = door.InsertionPoint.X* Unit;
                    standard1.TranslateY = door.InsertionPoint.Y * Unit;
                    standard1.TranslateZ = door.InsertionPoint.Z * Unit;
                    standard1.RotateZ = door.Rotation;

                    var points = door.Line.Points.Select(s => new Point(s.X * 0.01, s.Y * 0.01)).ToList();
                    var profile = tool.GetLineProfile(points, door.Line.Width * Unit);

                    var pathIn = tool.GetLinePath(
         door.Type, door.Width * Unit, door.Thickness * Unit, door.Height * Unit, door.SillHeight * Unit,
         door.InInterval * Unit, door.InInterval * Unit + door.OutInterval * Unit,
         door.Line.Width * Unit, door.Line.InHeight * Unit, door.Jambs.Thickness * Unit, door.Leaf.Thickness * Unit, LeafNumber, true);

                    var visualModel = new ModelVisual3D();
                    visualModel.Transform = standard1.Transform;
                    var model1 = new GeometryModel3D();
                    visualModel.Content = model1;
                    model1.Geometry = SD4_MeshTool.ExtrudeAlongPath(profile, pathIn, new Vector3D(0, 1, 0));
                    model1.Material = new DiffuseMaterial() { Brush = Brushes.Black };
                    model1.BackMaterial = new DiffuseMaterial { Brush = Brushes.Azure };





                    this.MainViewRoot.Children.Add(visualModel);

                    var pathOut = tool.GetLinePath(door.Type, door.Width * Unit, door.Thickness * Unit, door.Height * Unit, door.SillHeight * Unit,
         door.InInterval * Unit, door.InInterval * Unit + door.OutInterval * Unit,
         door.Line.Width * Unit, door.Line.InHeight * Unit, door.Jambs.Thickness * Unit, door.Leaf.Thickness * Unit, LeafNumber, true);
                    var visualModel2 = new ModelVisual3D();
                    visualModel2.Transform = standard1.Transform;
                    var model2 = new GeometryModel3D();
                    visualModel2.Content = model2;
                    model2.Geometry = SD4_MeshTool.ExtrudeAlongPath(profile, pathOut, new Vector3D(0, 1, 0));
                    model2.Material = new DiffuseMaterial { Brush = Brushes.Azure };
                    model2.BackMaterial = new DiffuseMaterial { Brush = Brushes.OrangeRed };
                    model2.Transform = new StandardTransform3D { RotateZ = 180, }.Transform;
                    this.MainViewRoot.Children.Add(visualModel2);
                    //门框
                    {
                        var profilemk = tool.GetJambsProfile(
      door.Type, door.Jambs.Type, door.Thickness * Unit, door.InInterval * Unit, door.OutInterval * Unit,
      door.Jambs.Thickness * Unit, door.Leaf.Thickness * Unit, LeafNumber);
                        if (profilemk != null && profilemk.Count > 0)
                        {
                            //var modelMk = new ContentVisual3D() {};
                            
                        
                            var geoMK = new GeometryModel3D();
                            var modelMk = geoMK.CreateContentVisual3D();
                            modelMk.SetName("test");
                            var pathmk = tool.GetJambsPath(door.Width * Unit, door.Height * Unit, door.SillHeight * Unit);
                            geoMK.Geometry = SD4_MeshTool.ExtrudeAlongPath(profilemk, pathmk, new Vector3D(-1, 0, 0));
                            geoMK.Material = new DiffuseMaterial() { Brush = Brushes.Black };
                            geoMK.BackMaterial = new DiffuseMaterial() { Brush = Brushes.Lavender };
                            //modelMk.Content = geoMK;
                            modelMk.Transform = standard1.Transform;
                            this.MainViewRoot.Children.Add(modelMk);
                            var ps = new Point3DCollection();
                            EdgeLinesFactory.AddEdgeLinePositions(geoMK, 45,ps);
                        }
                    }
                    //门
                    {

                    }
               


                }
             



                #endregion
            }


            //切片
            {
                foreach (var item in data.Symbol.Slices)
                {
                    //var slice = new Slice() ;
                    //if (project.Data.IdentifyAreas.Count > 2)
                    //{
                    //    var avgX = project.Data.IdentifyAreas.Average(it => it.X);
                    //    var maxY = project.Data.IdentifyAreas.Max(it => it.Y);
                    //    var minY = project.Data.IdentifyAreas.Min(it => it.Y);


                    //    slice.StartPoint = new Scad4.Models. Point3(avgX, maxY + 1, 0);
                    //    slice.FinalPoint = new Scad4.Models.Point3(avgX, minY - 1, 0);
                    //}
                    //else
                    //{
                    //    slice.StartPoint = new Scad4.Models.Point3(0, -5, 0);
                    //    slice.FinalPoint = new Scad4.Models.Point3(0, 5, 0);
                    //}
                    

                    var vm = new ScadSliceViewModel(item);
                    var vs = new VisualSlice(project, vm);
                    vs.SetName("slice");
                    this.MainViewRoot.Children.Add(vs);
                }

            }

            //栏杆
            {
                var root = this.MainViewRoot.Children;
                foreach (var balustrade in project.Data.Construction.Balustrades)
                {
                    var vm = new ScadBalustradeViewModel(balustrade, new ResourceModelService(new LoggerService()));
                    var visual = new VisualBalustrade(project, vm);
                    root.Add(visual);
                    //生成栏杆顶墙
                    root.Add(new VisualBalustradeWallUpper(visual));
                    //生成栏杆顶板
                    root.Add(new VisualBalustradeFloorUpper(visual));
                    //生成栏杆底墙
                    root.Add(new VisualBalustradeWallLower(visual));
                    //生成栏杆底板
                    root.Add(new VisualBalustradeFloorLower(visual));
                }
            }
       

        }
        private const string ModelPath = "Assets/Model3D/{0}.dae";
        void AddHoles()
        {

        }

        static float Unit=0.01f;

        public void CreateVerticalFlats(MeshGeometry3D mesh,
    IList<Point> points,
    double upperHeight=height, double lowerHeight=0,
    bool invertFace = false, StandardTransform3D standardTransform = null)
        {
            if (null == points || 2 > points.Count) throw new Exception("无法生成墙体，少于2个定位");
            var count = points.Count;
            var indexAdd = invertFace ?
                new int[] { 0, 2, 1, 3, 2, 0 } : [0, 1, 2, 3, 0, 2];

            for (int i = 0; i < count; i++)
            {
                var point1 = points[i];
                var next = i + 1;
                if (next == count) next = 0;
                var point2 = points[next];

                var index = mesh.Positions.Count;
            

                mesh.Positions.Add(new Point3D(point1.X, point1.Y, lowerHeight));
                mesh.Positions.Add(new Point3D(point2.X, point2.Y, lowerHeight));
                mesh.Positions.Add(new Point3D(point2.X, point2.Y, upperHeight));
                mesh.Positions.Add(new Point3D(point1.X, point1.Y, upperHeight));

                //mesh.Normals.Add(normal);
                //mesh.Normals.Add(normal);
                //mesh.Normals.Add(normal);
                //mesh.Normals.Add(normal);

                mesh.TriangleIndices.Add(index + indexAdd[0]);
                mesh.TriangleIndices.Add(index + indexAdd[1]);
                mesh.TriangleIndices.Add(index + indexAdd[2]);
                mesh.TriangleIndices.Add(index + indexAdd[3]);
                mesh.TriangleIndices.Add(index + indexAdd[4]);
                mesh.TriangleIndices.Add(index + indexAdd[5]);

                var model = new GeometryModel3D();
                model.Material = new DiffuseMaterial() { Brush = new SolidColorBrush(Color.FromRgb(230, 237, 240)) };
                model.BackMaterial = new DiffuseMaterial() { Brush = new SolidColorBrush(Color.FromRgb(230, 237, 240)) };
                model.Geometry = mesh;

                if (standardTransform != null)
                {
                    model.Transform = standardTransform.Transform;
                }

                this.Group.Children.Add(model);
            }
        }


        public static List<Point3D> Point2DTo3D(IList<Point> points, double z = 2)
        {
            var result = new List<Point3D>();
            foreach (var point in points)
            {
                result.Add(new Point3D(point.X, point.Y, z));
            }
            return result;
        }
        void Create3D(List<Point> points,List<Point3D> pontis3D, List<Point> holePoints,bool isHold=false,Brush brush=null, StandardTransform3D standardTransform=null)
        {
            
            var model = new GeometryModel3D();

            var mesh = new MeshGeometry3D();



            Triangulator t = new Triangulator(points);
            if (isHold)
            {
                t.AddHole(new PointCollection(holePoints));

                t.Triangulate(out PointCollection pp, out List<int> pps);
                mesh.TriangleIndices = new Int32Collection(pps);

                var newPoint3D = Point2DTo3D(pp,30);

                mesh.Positions = new Point3DCollection(newPoint3D);
                model.Material = new DiffuseMaterial() { Brush = Brushes.LightCoral };
                model.BackMaterial = new DiffuseMaterial() { Brush = Brushes.LightCoral };
            }
            else
            {
                var indices = t.CreateTriangleIndices();
                mesh.TriangleIndices = new Int32Collection(indices);
                mesh.Positions = new Point3DCollection(pontis3D);
                model.Material = new DiffuseMaterial() { Brush =brush==null? Brushes.LightGray:Brushes.LightCoral };
                model.BackMaterial = new DiffuseMaterial() { Brush = brush == null ?  Brushes.LightBlue:Brushes.Brown };
            }


            if (standardTransform != null)
            {
                model.Transform = standardTransform.Transform;
            }

          
            model.Geometry = mesh;

            this.Group.Children.Add(model);
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
           var model= this.MainViewRoot.Children.Where(s => ((ModelVisual3D)s).GetName() == "test").ToList();


            for (int i = 0; i < model.Count(); i++)
            {
               // var temp = model[i];
                if (model[i] is ContentVisual3D d)
                {
                    d.IsVisible = false;
                }
            }

            //foreach (var item in model)
            //{
            //   if(item is ModelVisual3D d)
            //    {
            //        this.MainViewRoot.Children.Remove(d);   
            //    }
            //}
        }
    }
    public class Wall
    {

        /// <summary>
        /// 墙体类型
        /// </summary>
        [JsonProperty("wallType")]
        public int Type { get; set; } 

        /// <summary>
        /// 墙体高度
        /// </summary>
        [JsonProperty(nameof(Height))]
        public double Height { get; set; }

        [JsonProperty("InLines")]
        public List<List<Point3>> InLines { get; set; }

        /// <summary>
        /// 墙体外侧点表
        /// </summary>
        [JsonProperty("OutLine")]
        public List<Point3> Edges { get; set; } 

    }

    public class ScadDataConstruction
    {
        /// <summary>
        /// 墙体
        /// </summary>
        [JsonProperty("walls")]
        public List<Wall> Walls { get; set; } = [];

        [JsonProperty("groundFloor")]
        public groundFloor groundFloor { get; set; }

        public List<BaseWindow> BaseWindow { get; set; }

        [JsonProperty("doors")]
        public List<Door> Doors { get; set; }
        
    }



    public class ScadData
    {
        /// <summary>
        /// 建筑
        /// </summary>
        [JsonProperty("construction")]
        public ScadDataConstruction Construction { get; set; } = new();

        [JsonProperty("IdentifyAreas")]
        public List<Point3> IdentifyAreas { get; set; }

     

    }

  





    /// <summary>
    /// 三维点
    /// </summary>
    [JsonConverter(typeof(Point3Converter))]
    public struct Point3(double x, double y, double z)
    {
        public double X { get; set; } = x;
        public double Y { get; set; } = y;
        public double Z { get; set; } = z;

        public static Point3 Parse(string code)
        {
            
            var codes = code.Split(',');
            return new Point3
            {
                X = double.Parse(codes[0]),
                Y = double.Parse(codes[1]),
                Z = double.Parse(codes[2])
            };
        }

        public override readonly string ToString()
        {
            return $"{X:F3},{Y:F3},{Z:F3}";
        }

        
    }


    public class Point3Converter : JsonConverter<Point3>
    {

        public override Point3 ReadJson(JsonReader reader, Type objectType, Point3 existingValue, bool hasExistingValue, JsonSerializer serializer)
        {
            var json = reader.Value?.ToString();
            if (json != null) return Point3.Parse(json);
            else return new Point3();
        }

        public override void WriteJson(JsonWriter writer, Point3 value, JsonSerializer serializer)
        {
            writer.WriteValue(value.ToString());
        }
    }

    public struct IdentifyAreas
    {
        public double X { get; set; }

        public double Y { get; set; }

        public static IdentifyAreas Parse(string code)
        {
            var codes = code.Split(',');
            return new IdentifyAreas
            {
                X = double.Parse(codes[0]),
                Y = double.Parse(codes[1]),
            };
        }
    }

    public class IdentifyAreasConverter : JsonConverter<IdentifyAreas>
    {

        public override IdentifyAreas ReadJson(JsonReader reader, Type objectType, IdentifyAreas existingValue, bool hasExistingValue, JsonSerializer serializer)
        {
            var json = reader.Value?.ToString();
            if (json != null) return IdentifyAreas.Parse(json);
            else return new IdentifyAreas();
        }

        public override void WriteJson(JsonWriter writer, IdentifyAreas value, JsonSerializer serializer)
        {
            writer.WriteValue(value.ToString());
        }
    }

}


